# 2.使用深度学习开源框架keras，基于MNIST数据,完成VGG16网络模型训练和评估
from keras.datasets.mnist import load_data
from keras import Sequential, models, Model, layers, activations, optimizers, losses

# ①导入项目中会用到的开源工具包
# ②读取keras内置数据
(x_train, y_train), (x_test, y_test) = load_data()
# ③对图像像素值进行浮点型处理，归一化处理，及结构重组处理
x_train = x_train.reshape(-1, 28, 28, 1) / 255
x_test = x_test.reshape(-1, 28, 28, 1) / 255
print()


# ④参考下图创建VGG16类封装模型，根据图像数据实际情况选取合适的卷积层数
# ⑤通道数以16为起始，每组翻倍
# ⑥每层卷积均采用3*3卷积核，步长均为1，padding均为same
# ⑦每组卷积后接最大池化层，池化核2*2，步长为2
# ⑧VGG16模型结构与参数信息
class VGG16(Model):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.conv = Sequential([
            layers.Conv2D(filters=16, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.Conv2D(filters=16, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.MaxPooling2D(),
            layers.Conv2D(filters=32, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.Conv2D(filters=32, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.MaxPooling2D(),
            layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.MaxPooling2D(),
            layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation=activations.relu),
            layers.MaxPooling2D()
        ])
        self.flat = Sequential(layers.Flatten())
        self.fc = Sequential([
            layers.Dense(units=4096, activation=activations.relu),
            layers.Dense(units=4096, activation=activations.relu),
            layers.Dense(units=10, activation=activations.softmax)
        ])

    def call(self, inputs, training=None, mask=None):
        out = self.conv(inputs)
        out = self.flat(out)
        out = self.fc(out)
        return out


model = VGG16()
model.build(input_shape=[None, 28, 28, 1])
model.summary()
# ⑨使用训练集进行模型训练，参数自拟
# ⑩计算并打印测试集最终的损失值和准确率
#
model.compile(optimizer=optimizers.Adam(), loss=losses.sparse_categorical_crossentropy,metrics='acc')
model.fit(x_train, y_train, batch_size=100, epochs=10)
model.evaluate(x_test, y_test)
